﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using CMWA.Packager;
using TopMachine.Topping.Dto;
using TopMachine.Desktop.Overall;
using System.Data.Common;
using System.Data.SqlClient;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;
using db4oProviders;
using Topping.Web.Security.db4o;

namespace Topping.Core.Data.Db4o
{
    public class ToppingAccessor: IDisposable 
    {

         public string dbFile = "";
         public IObjectContainer entity = null;
         private string _ApplicationName = "TOPMACHINE";
         private string _roleName = "Admin";

         public ToppingAccessor(string path)
         {
             entity = new SafeDB(path);  
         }
        public ToppingAccessor()
        {
            string conn; 
            string key;
            //if (System.Configuration.ConfigurationManager.AppSettings["PackageOnServer"] == "1")
            //{
            //    key = "SqlLite";
            //}
            //else 
            //{
                key = "Db4o";
            //}
            if (System.Configuration.ConfigurationManager.ConnectionStrings[key] != null)
            {
                conn = System.Configuration.ConfigurationManager.ConnectionStrings[key].ConnectionString;
            }
            else 
            {
                conn = PackageManager.Instance.Project.GetFileName("TopMachineData\\Databases\\Topping4dbo");
                           
            }
                //    string p = AppDomain.CurrentDomain.BaseDirectory + "\\App_Data\\Topping.db";
                //    dbFile = p;
                //}
                //else
                //{
                //    string db = PackageManager.Instance.Project.GetFileName("TopMachineData\\Databases\\Topping4dbo");
                //    dbFile = db;
                //}

             entity = new SafeDB(conn);  
                //GetObjectContainer();
        }

    
        public  IObjectContainer GetObjectContainer()
        {
            if (entity == null )
            {    
                    
                entity = Db4oEmbedded.OpenFile(dbFile);
            }

            return entity; 
        }

   
        #region Configuration
        public List<ConfigGameDto> GetConfigurations()
        {
            List<ConfigGameDto> list = new List<ConfigGameDto>();
            var result = from GameConfig p in entity select p;

            foreach (GameConfig cfg in result)
            {
                ConfigGameDto dto = new ObjectSerializer<ConfigGameDto>().Deserialize(cfg.XmlConfig);
                list.Add(dto);
            }

            return list;
        }
        public bool AddConfiguration(GameConfig  cfg) 
        {
            try
            {
                entity.Store(cfg);
                return true;
            }
            catch (Exception ex) 
            {
                return false;
            } 
        }
        public bool UpdateConfiguration(ConfigGameDto cfg)
        {
            try
            {
                GameConfig row = null;

                if (cfg.Id == Guid.Empty)
                {
                    row = new GameConfig();
                    row.Id = Guid.NewGuid();
                    cfg.Id = row.Id;
                }
                else
                {
                    row = (from GameConfig p in entity where p.Id == cfg.Id select p).FirstOrDefault();
                }

                row.XmlConfig = new ObjectSerializer<ConfigGameDto>().Serialize(cfg);

                entity.Store(row);
            }
            catch (Exception)
            {

                return false;
            }

            return true;
        }

        public bool DeleteConfiguration(ConfigGameDto cfg)
        {
            try
            {
                    GameConfig row = null;
                    row = (from GameConfig p in entity where p.Id == cfg.Id select p).FirstOrDefault();
                    if (row != null)
                    {
                        entity.Delete(row);
                    }

            }
            catch (Exception)
            {
                return false;
            }

            return true;

        }

        public List<RankingDto> GetRankings(string player, int year, int mont, Guid configId)
        {
            Guid pid = 
                (from db4oProviders.User u in entity where u.Username == player select u.PKID)
                            .FirstOrDefault();

            List<GameRanking>query= null;

            if (player.Length > 0 && configId == Guid.Empty)
            {
                query =  (from GameRanking p in entity where
                               p.Playerid == pid && p.Year == year && p.Month == mont
                          select p).ToList(); ;
            }

            if (player.Length > 0 && configId != Guid.Empty)
            {
                query = (from GameRanking p in entity where p.Playerid == pid && p.ConfigGameId == configId select p).ToList();
            }

            List<RankingDto> dto = new List<RankingDto>();
            Console.Write(query.Count); 

            foreach(GameRanking p in query)
            {
                    RankingDto d =new RankingDto()
                                    { BestScore = p.BestScore*100,
                                      BestTime = p.BestTime / 60 + ":" + p.BestTime % 60, 
                                     Config = p.ConfigGameId, 
                                     NbGames = p.NbParties, 
                                     NbLostTops = (float) p.LostTops / p.NbParties, 
                                     NbTops = p.TotalTops,
                                     Percentage = (float) p.PlayerTop / p.GameTop*100,
                                     Period = p.Month +  "/" + p.Year,
                                     Player = player }; 

                        int Time = p.Time / p.NbParties;
                        d.Time = Time / 60 + ":" + Time % 60;
                    dto.Add(d);
                                     
            }

            return dto; 

        }

        #endregion

        #region Game
        public List<GamesDetailDto> GetGamesDetail(string player, int year, int mont, Guid configId)
        {

            Guid pid =
                (from db4oProviders.User u in entity where u.Username == player select u.PKID)
                            .FirstOrDefault();


            List<GamesDetail> query = null;

            DateTime start = new DateTime(year, mont, 1);
            DateTime end = start.AddMonths(1);

            query = (from GamesDetail p in entity where 
                            (p.Date >= start && p.Date < end) 
                            && p.UserId == pid && p.GameConfigId == configId select p).ToList();

            List<GamesDetailDto> dto = new List<GamesDetailDto>();
            Console.Write(query.Count);

            foreach (GamesDetail p in query)
            {
                GamesDetailDto d = new GamesDetailDto()
                {
                    Date = p.Date,
                    Percentage = (float)p.Percentage.GetValueOrDefault(0),
                    UserName = player,
                    Negative = (int)p.Negative.GetValueOrDefault(0),
                    Total = (int)p.Total.GetValueOrDefault(0),
                    Top = (int)p.Top.GetValueOrDefault(0),
                    GameId = p.GameId,
                    TopLost = (int)p.TopLost.GetValueOrDefault(0),
                    ConfigId = p.GameConfigId
                };

                d.Time = p.Time / 60 + ":" + p.Time % 60;

                dto.Add(d);

            }

            return dto;

        }

        public void AddGame(GeneratedGameDto gameDto)
        {
            if (gameDto.Config.HistoryGame)
            {
                Game game = new Game()
                {
                    Date = gameDto.DateTime,
                    GameConfigId = gameDto.Config.Id,
                    GameId = gameDto.Id,
                    Status = (int)gameDto.Status,
                    Name = gameDto.Name,
                };

                game.GameXml = new ObjectSerializer<GeneratedGameDto>().Serialize(gameDto);

                entity.Store(game);
            }

        }

        public void FinishGame(string player, GeneratedGameDto game, PlayerSummaryDto sum, bool doDetail, bool doHistory, bool doStats)
        {
            if (sum.Turn == 0) return; 

            db4oProviders.User vid = (from db4oProviders.User p in entity where p.Username == player select p).FirstOrDefault();
            
            if (vid != null)
            {
                DateTime n = DateTime.Now;

                GamesDetail detail = new GamesDetail();

                if (doDetail)
                {
                    detail.DetailXml = new ObjectSerializer<List<PlayedGameRoundDto>>().Serialize(sum.Rounds);
                }

                int top = game.Rounds.Sum(p => p.Points);
                detail.Date = n;
                detail.GameId = game.Id;
                detail.Negative = sum.PointsLost;
                detail.Percentage = (double)sum.Total / top;
                detail.Time = (long)sum.Time;
                detail.Top = sum.Total;
                detail.TopLost = game.Rounds.Count - sum.TotalTop;
                detail.UserId = vid.PKID;
                detail.GameConfigId = game.Config.Id; 

                sum.Percentage = (float) detail.Percentage; 

                if (doHistory)
                {
                    entity.Store(detail);
                }

                if (doStats)
                {
                    GameRanking rnk = (from GameRanking p in entity where
                                p.Year == n.Year && p.Month == n.Month && p.ConfigGameId == game.Config.Id 
                                && p.Playerid == vid.PKID select p).FirstOrDefault();

                    if (rnk == null)
                    {
                        rnk = new GameRanking()
                        {
                            Year = n.Year,
                            Month = n.Month,
                            ConfigGameId = game.Config.Id,
                            Playerid = vid.PKID
                        };
                    }


                    rnk.NbParties++;
                    rnk.LostTops += detail.TopLost.GetValueOrDefault(0);
                    rnk.Time += (int)detail.Time.GetValueOrDefault(0);
                    if (detail.Percentage == 1) rnk.TotalTops++;
                    rnk.PlayerTop += (int)detail.Top;
                    rnk.GameTop += top;
                    rnk.Percentage = (float)rnk.PlayerTop / rnk.GameTop;


                    if (rnk.BestScore <= detail.Percentage)
                    {
                        rnk.BestScore = detail.Percentage.GetValueOrDefault();
                        if (rnk.BestTime == 0 || rnk.BestTime > detail.Time.GetValueOrDefault())
                        {
                            rnk.BestTime = (int)detail.Time.GetValueOrDefault();
                        }
                    }

                    entity.Store(rnk);
                }
            }

        }
        #endregion

        #region User

        public db4oProviders.User GetUser(string UserName)
        {
            var list_user = (from db4oProviders.User u in entity where u.Username == UserName select u);
            if (list_user.Count() > 0) 
            {
                return list_user.First();  
            }

            return null;
        }

        public db4oProviders.User GetUser(Guid pkid)
        {
            return (db4oProviders.User)(from db4oProviders.User u in entity where u.PKID == pkid select u).First() ;
        }

        public List<db4oProviders.User> GetUsers()
        {
            return (from db4oProviders.User u in entity select u).ToList();
        }
        public db4oProviders.EnrolledUser getEnrolledUser(db4oProviders.User us) 
        { 
         var lst =  (from db4oProviders.EnrolledUser eu in entity 
                                                    where eu.Username == us.Username 
                                                         && eu.ApplicationName == _ApplicationName 
                                                    select eu);
         if (lst.Count()  > 0)
         {
             return lst.First();
         }
         else 
         {
             return null;
         }
        }

        public bool IsAdminUser(db4oProviders.User us) 
        {
            db4oProviders.EnrolledUser en = getEnrolledUser(us);
            if (en != null)
            {
                return en.Roles.Contains(_roleName);
            }

            return false;
        }
        public bool ChangedPwdUsers(db4oProviders.User us, string newPWD) 
        {
            try
            {
                us.Password = db4oMembershipProvider.GetEncryption(newPWD);
                entity.Store(us);
            }
            catch (Exception)
            {

                return false;
            }

            return true;

        }

        public bool UpdateUsers(db4oProviders.User us,List<string> roles,db4oProviders.EnrolledUser en)
        {
            try
            {
                if (us.PKID == Guid.Empty)
                {
                    us.PKID = Guid.NewGuid();
                    us.ApplicationName = _ApplicationName;
                    us.IsApproved = true;
                    en = new EnrolledUser(us.Username, us.ApplicationName);   
                }
                entity.Store(us);

                if (en == null) 
                {
                    en = new EnrolledUser(us.Username, us.ApplicationName);
                   
                }

                if (roles != null) 
                {
                    en.Roles = roles;

                    entity.Store(en);  
                }          
                

            }
            catch (Exception)
            {

                return false;
            }

            return true;
        }

        public bool DeleteUsers(db4oProviders.User us)
        {
            try
            {
                if (us != null)
                {
                    entity.Delete(us);
                }
                else 
                {
                    return false;
                }

            }
            catch (Exception)
            {
                return false;
            }

            return true;

        }

        public bool Login(string userName, string passWord)
        {
            db4oProviders.User vid = (from db4oProviders.User p in entity where p.Username == userName select p).FirstOrDefault();
            
            if (vid == null)
            {
                db4oProviders.User u = new db4oProviders.User();
                u.PKID = Guids.SequentialGuid();
                u.Username = userName;

                entity.Store(u);
            }
            return true;
        }
        #endregion


        #region IDisposable Members

        public void Dispose()
        {
            if (entity != null)
            {
                entity.Dispose();
                entity = null;
            }
        }

        #endregion
    }
}
